import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from utils.csv_hanlder import select_and_read_files
from utils.convex_hanlder import calculate_convex_hull_area, polyarea
from utils.console_hanlder import console
from scipy.signal import find_peaks
import os
from scipy.spatial import ConvexHull


def plot_scatter_area_vs_f_linear(area, f, figsize=(12, 8), fig_name="result/area_vs_f_linear.png",
                                  smooth_window=21, prominence=0.05, distance=30, target_valley_count=(3,5)):
    """
    Plot the relationship between frequency and convex hull area using LINEAR scale, highlighting key minima.
    """
    # Data Preprocessing 
    df = pd.DataFrame({'f': f, 'area': area}).dropna().sort_values('f')
    f = df['f'].values
    area = df['area'].values

    # Ensure data is numeric
    df['f'] = pd.to_numeric(df['f'], errors='coerce')
    df['area'] = pd.to_numeric(df['area'], errors='coerce')
    df = df.dropna()
    
    if len(df) == 0:
        print("错误: 没有有效的数值数据可绘制")
        return

    f = df['f'].values
    area = df['area'].values

    # Smoothing 
    smooth_area = pd.Series(area).rolling(smooth_window, center=True, min_periods=1).mean().values

    # Find Global Minimum 
    min_idx = np.argmin(smooth_area)
    min_area = smooth_area[min_idx]
    min_freq = f[min_idx]

    # Adaptive Valley Detection 
    peaks_found = []
    adaptive_prom = prominence
    for _ in range(10):  # Maximum 10 attempts for auto-adjustment
        valleys, props = find_peaks(-smooth_area,
                                    prominence=adaptive_prom * np.ptp(smooth_area),
                                    distance=distance)
        if len(valleys) < target_valley_count[0]:
            adaptive_prom *= 0.7   # Loosen threshold
        elif len(valleys) > target_valley_count[1]:
            adaptive_prom *= 1.3   # Tighten threshold
        else:
            peaks_found = valleys
            break
    if len(peaks_found) == 0:
        peaks_found = valleys  # fallback
    
    local_freqs = f[peaks_found]
    local_areas = smooth_area[peaks_found]

    # Plotting 
    fig = plt.figure(figsize=figsize)
    grid = plt.GridSpec(4, 4, hspace=0.5, wspace=0.5)

    ax_main = fig.add_subplot(grid[1:4, 0:3])
    scatter = ax_main.scatter(f, area,
                             alpha=0.6,
                             c=area,
                             cmap='viridis',
                             s=50)

    # Mark global minimum (red star)
    ax_main.scatter(min_freq, min_area,
                   color='red', s=120, marker='*',
                   edgecolors='black', linewidth=2,
                   label=f'Global Minima: {min_area:.2e}\nFreq: {min_freq:.0f}')

    # Mark main valleys (orange triangles)
    ax_main.scatter(local_freqs, local_areas,
                   color='orange', s=80, marker='v',
                   edgecolors='black', linewidth=1.2,
                   label='Local Minima')

    ax_main.set_xlabel('Frequency [Hz]', fontsize=12)
    ax_main.set_ylabel('Convex Hull Area [mm²] (linear scale)', fontsize=12)
    ax_main.set_title('Frequency vs Convex Hull Area (Linear Scale)', fontsize=14)
    ax_main.grid(True, alpha=0.3)
    ax_main.legend()

    cbar = plt.colorbar(scatter, ax=ax_main)
    cbar.set_label('Convex Hull Area [mm²]', rotation=270, labelpad=15)

    # Frequency Histogram 
    ax_histx = fig.add_subplot(grid[0, 0:3])
    ax_histx.hist(f, bins=30, alpha=0.7, color='skyblue', edgecolor='black')
    ax_histx.axvline(min_freq, color='red', linestyle='--', linewidth=2)
    for freq in local_freqs:
        ax_histx.axvline(freq, color='orange', linestyle='--', linewidth=1)
    ax_histx.set_title('Distribution of Frequency [Hz]')
    ax_histx.set_ylabel('Count')

    # Area Histogram 
    ax_histy = fig.add_subplot(grid[1:4, 3])
    ax_histy.hist(area, bins=30, orientation='horizontal',
                 alpha=0.7, color='lightcoral', edgecolor='black')
    ax_histy.axhline(min_area, color='red', linestyle='--', linewidth=2)
    for a in local_areas:
        ax_histy.axhline(a, color='orange', linestyle='--', linewidth=1)
    ax_histy.set_title('Distribution of Convex Hull Area [mm²]')
    ax_histy.set_xlabel('Count')

    plt.tight_layout()
    if fig_name:
        # Ensure output directory exists
        os.makedirs(os.path.dirname(fig_name), exist_ok=True)
        plt.savefig(fig_name, dpi=300, bbox_inches='tight')
        print(f"Plot saved to: {fig_name}")
    plt.close(fig)

    # Save Results to file only
    console.log_detailed_results("=" * 60)
    console.log_detailed_results("凸包面积统计 (线性尺度):")
    console.log_detailed_results(f"全局最小面积: {min_area:.2e} mm²")
    console.log_detailed_results(f"对应频率: {min_freq:.0f} Hz")
    console.log_detailed_results(f"平均面积: {np.mean(area):.2e} mm², 标准差: {np.std(area):.2e} mm²")
    console.log_detailed_results(f"平均频率: {np.mean(f):.0f} Hz, 标准差: {np.std(f):.2e} Hz")
    console.log_detailed_results("=" * 60)
    console.log_detailed_results(f"检测到 {len(local_freqs)} 个局部最小值 (目标 {target_valley_count[0]}-{target_valley_count[1]}):")
    for i, (freq, a) in enumerate(zip(local_freqs, local_areas), 1):
        console.log_detailed_results(f"  {i:02d}) 频率={freq:.0f} Hz, 面积={a:.2e} mm²")
    console.log_detailed_results("=" * 60)


def plot_scatter_area_vs_f_log(area, f, figsize=(12, 8), fig_name="result/area_vs_f_log.png",
                               smooth_window=21, prominence=0.05, distance=30, target_valley_count=(3,5)):
    """
    Plot the relationship between frequency and convex hull area using LOG scale, highlighting key minima.
    """
    # Data Preprocessing 
    df = pd.DataFrame({'f': f, 'area': area}).dropna().sort_values('f')
    f = df['f'].values
    area = df['area'].values

    # Ensure data is numeric
    df['f'] = pd.to_numeric(df['f'], errors='coerce')
    df['area'] = pd.to_numeric(df['area'], errors='coerce')
    df = df.dropna()
    
    if len(df) == 0:
        print("错误: 没有有效的数值数据可绘制")
        return

    f = df['f'].values
    area = df['area'].values

    # Smoothing 
    smooth_area = pd.Series(area).rolling(smooth_window, center=True, min_periods=1).mean().values

    # Find Global Minimum 
    min_idx = np.argmin(smooth_area)
    min_area = smooth_area[min_idx]
    min_freq = f[min_idx]

    # Adaptive Valley Detection 
    peaks_found = []
    adaptive_prom = prominence
    for _ in range(10):  # Maximum 10 attempts for auto-adjustment
        valleys, props = find_peaks(-smooth_area,
                                    prominence=adaptive_prom * np.ptp(smooth_area),
                                    distance=distance)
        if len(valleys) < target_valley_count[0]:
            adaptive_prom *= 0.7   # Loosen threshold
        elif len(valleys) > target_valley_count[1]:
            adaptive_prom *= 1.3   # Tighten threshold
        else:
            peaks_found = valleys
            break
    if len(peaks_found) == 0:
        peaks_found = valleys  # fallback
    
    local_freqs = f[peaks_found]
    local_areas = smooth_area[peaks_found]

    # Plotting 
    fig = plt.figure(figsize=figsize)
    grid = plt.GridSpec(4, 4, hspace=0.5, wspace=0.5)

    ax_main = fig.add_subplot(grid[1:4, 0:3])
    scatter = ax_main.scatter(f, area,
                             alpha=0.6,
                             c=area,
                             cmap='viridis',
                             s=50)

    # Mark global minimum (red star)
    ax_main.scatter(min_freq, min_area,
                   color='red', s=120, marker='*',
                   edgecolors='black', linewidth=2,
                   label=f'Global Minima: {min_area:.2e}\nFreq: {min_freq:.0f}')

    # Mark main valleys (orange triangles)
    ax_main.scatter(local_freqs, local_areas,
                   color='orange', s=80, marker='v',
                   edgecolors='black', linewidth=1.2,
                   label='Local Minima')

    ax_main.set_xlabel('Frequency [Hz]', fontsize=12)
    ax_main.set_ylabel('Convex Hull Area [mm²] (log scale)', fontsize=12)
    ax_main.set_title('Frequency vs Convex Hull Area (Log Scale)', fontsize=14)
    ax_main.set_yscale('log')  # Set log scale for y-axis
    ax_main.grid(True, alpha=0.3)
    ax_main.legend()

    cbar = plt.colorbar(scatter, ax=ax_main)
    cbar.set_label('Convex Hull Area [mm²]', rotation=270, labelpad=15)

    # Frequency Histogram 
    ax_histx = fig.add_subplot(grid[0, 0:3])
    ax_histx.hist(f, bins=30, alpha=0.7, color='skyblue', edgecolor='black')
    ax_histx.axvline(min_freq, color='red', linestyle='--', linewidth=2)
    for freq in local_freqs:
        ax_histx.axvline(freq, color='orange', linestyle='--', linewidth=1)
    ax_histx.set_title('Distribution of Frequency [Hz]')
    ax_histx.set_ylabel('Count')

    # Area Histogram (log scale)
    ax_histy = fig.add_subplot(grid[1:4, 3])
    ax_histy.hist(area, bins=30, orientation='horizontal',
                 alpha=0.7, color='lightcoral', edgecolor='black')
    ax_histy.axhline(min_area, color='red', linestyle='--', linewidth=2)
    for a in local_areas:
        ax_histy.axhline(a, color='orange', linestyle='--', linewidth=1)
    ax_histy.set_title('Distribution of Convex Hull Area [mm²]')
    ax_histy.set_xlabel('Count')
    ax_histy.set_yscale('log')  # Set log scale for histogram

    plt.tight_layout()
    if fig_name:
        # Ensure output directory exists
        os.makedirs(os.path.dirname(fig_name), exist_ok=True)
        plt.savefig(fig_name, dpi=300, bbox_inches='tight')
        print(f"Plot saved to: {fig_name}")
    plt.close(fig)

    # Save Results to file only
    console.log_detailed_results("=" * 60)
    console.log_detailed_results("凸包面积统计 (对数尺度):")
    console.log_detailed_results(f"全局最小面积: {min_area:.2e} mm²")
    console.log_detailed_results(f"对应频率: {min_freq:.0f} Hz")
    console.log_detailed_results(f"平均面积: {np.mean(area):.2e} mm², 标准差: {np.std(area):.2e} mm²")
    console.log_detailed_results(f"平均频率: {np.mean(f):.0f} Hz, 标准差: {np.std(f):.2e} Hz")
    console.log_detailed_results("=" * 60)
    console.log_detailed_results(f"检测到 {len(local_freqs)} 个局部最小值 (目标 {target_valley_count[0]}-{target_valley_count[1]}):")
    for i, (freq, a) in enumerate(zip(local_freqs, local_areas), 1):
        console.log_detailed_results(f"  {i:02d}) 频率={freq:.0f} Hz, 面积={a:.2e} mm²")
    console.log_detailed_results("=" * 60)


def plot_scatter_area_vs_f(area, f, figsize=(12, 8), fig_name="result/area_vs_f.png",
                           smooth_window=21, prominence=0.05, distance=30, target_valley_count=(3,5)):
    """
    Plot the relationship between frequency and convex hull area, highlighting key minima.
    """

    # Data Preprocessing 
    df = pd.DataFrame({'f': f, 'area': area}).dropna().sort_values('f')
    f = df['f'].values
    area = df['area'].values

    # Ensure data is numeric
    df['f'] = pd.to_numeric(df['f'], errors='coerce')
    df['area'] = pd.to_numeric(df['area'], errors='coerce')
    df = df.dropna()
    
    if len(df) == 0:
        print("错误: 没有有效的数值数据可绘制")
        return

    f = df['f'].values
    area = df['area'].values

    # Smoothing 
    smooth_area = pd.Series(area).rolling(smooth_window, center=True, min_periods=1).mean().values

    # Find Global Minimum 
    min_idx = np.argmin(smooth_area)
    min_area = smooth_area[min_idx]
    min_freq = f[min_idx]

    # Adaptive Valley Detection 
    peaks_found = []
    adaptive_prom = prominence
    for _ in range(10):  # Maximum 10 attempts for auto-adjustment
        valleys, props = find_peaks(-smooth_area,
                                    prominence=adaptive_prom * np.ptp(smooth_area),
                                    distance=distance)
        if len(valleys) < target_valley_count[0]:
            adaptive_prom *= 0.7   # Loosen threshold
        elif len(valleys) > target_valley_count[1]:
            adaptive_prom *= 1.3   # Tighten threshold
        else:
            peaks_found = valleys
            break
    if len(peaks_found) == 0:
        peaks_found = valleys  # fallback
    
    local_freqs = f[peaks_found]
    local_areas = smooth_area[peaks_found]

    # Plotting 
    fig = plt.figure(figsize=figsize)
    grid = plt.GridSpec(4, 4, hspace=0.5, wspace=0.5)

    ax_main = fig.add_subplot(grid[1:4, 0:3])
    scatter = ax_main.scatter(f, area,
                             alpha=0.6,
                             c=area,
                             cmap='viridis',
                             s=50)

    # Mark global minimum (red star)
    ax_main.scatter(min_freq, min_area,
                   color='red', s=120, marker='*',
                   edgecolors='black', linewidth=2,
                   label=f'Global Minima: {min_area:.2e}\nFreq: {min_freq:.0f}')

    # Mark main valleys (orange triangles)
    ax_main.scatter(local_freqs, local_areas,
                   color='orange', s=80, marker='v',
                   edgecolors='black', linewidth=1.2,
                   label='Local Minima')

    ax_main.set_xlabel('Frequency', fontsize=12)
    ax_main.set_ylabel('Convex Hull Area', fontsize=12)
    ax_main.set_title('Frequency vs Convex Hull Area', fontsize=14)
    ax_main.grid(True, alpha=0.3)
    ax_main.legend()

    cbar = plt.colorbar(scatter, ax=ax_main)
    cbar.set_label('Convex Hull Area', rotation=270, labelpad=15)

    # Frequency Histogram 
    ax_histx = fig.add_subplot(grid[0, 0:3])
    ax_histx.hist(f, bins=30, alpha=0.7, color='skyblue', edgecolor='black')
    ax_histx.axvline(min_freq, color='red', linestyle='--', linewidth=2)
    for freq in local_freqs:
        ax_histx.axvline(freq, color='orange', linestyle='--', linewidth=1)
    ax_histx.set_title('Distribution of Frequency')
    ax_histx.set_ylabel('Count')

    # Area Histogram 
    ax_histy = fig.add_subplot(grid[1:4, 3])
    ax_histy.hist(area, bins=30, orientation='horizontal',
                 alpha=0.7, color='lightcoral', edgecolor='black')
    ax_histy.axhline(min_area, color='red', linestyle='--', linewidth=2)
    for a in local_areas:
        ax_histy.axhline(a, color='orange', linestyle='--', linewidth=1)
    ax_histy.set_title('Distribution of Convex Hull Area')
    ax_histy.set_xlabel('Count')

    plt.tight_layout()
    if fig_name:
        # Ensure output directory exists
        os.makedirs(os.path.dirname(fig_name), exist_ok=True)
        plt.savefig(fig_name, dpi=300, bbox_inches='tight')
        print(f"Plot saved to: {fig_name}")
    plt.close(fig)

    # Save Results to file only
    console.log_detailed_results("=" * 60)
    console.log_detailed_results("凸包面积统计:")
    console.log_detailed_results(f"全局最小面积: {min_area:.2e}")
    console.log_detailed_results(f"对应频率: {min_freq:.0f}")
    console.log_detailed_results(f"平均面积: {np.mean(area):.2e}, 标准差: {np.std(area):.2e}")
    console.log_detailed_results(f"平均频率: {np.mean(f):.0f}, 标准差: {np.std(f):.2e}")
    console.log_detailed_results("=" * 60)
    console.log_detailed_results(f"检测到 {len(local_freqs)} 个局部最小值 (目标 {target_valley_count[0]}-{target_valley_count[1]}):")
    for i, (freq, a) in enumerate(zip(local_freqs, local_areas), 1):
        console.log_detailed_results(f"  {i:02d}) 频率={freq:.0f}, 面积={a:.2e}")
    console.log_detailed_results("=" * 60)


def process_files_and_plot_area(dfs, filenames=None, batch_size=200):
    """
    Process multiple dataframes to calculate convex hull areas and plot vs frequency.
    """
    areas = []
    frequencies = []
    hull_vertices_list = []
    total_files = len(dfs)
    
    console.log_section("凸包面积分析")
    console.log(f"使用批次大小 {batch_size} 处理 {total_files} 个文件")
    
    # Process files in batches for better performance
    for batch_start in range(0, total_files, batch_size):
        batch_end = min(batch_start + batch_size, total_files)
        batch_dfs = dfs[batch_start:batch_end]
        batch_filenames = filenames[batch_start:batch_end] if filenames else None
        
        for idx, df in enumerate(batch_dfs):
            global_idx = batch_start + idx
            try:
                # Get frequency (assuming it's constant within each file)
                f_val = df['f'].iloc[0]
                
                # Calculate convex hull area from x and y coordinates
                x = df['x'].values
                y = df['y'].values
                
                # Calculate convex hull area and get vertices
                convex_hull_area = calculate_convex_hull_area(x, y)
                
                # Skip vertices calculation for speed
                hull_vertices = None
                
                frequencies.append(f_val)
                areas.append(convex_hull_area)
                hull_vertices_list.append(hull_vertices)
                
                # Log every 50th file to reduce console spam
                if (global_idx + 1) % 50 == 0:
                    filename = batch_filenames[idx] if batch_filenames else f'文件 {global_idx+1}'
                    console.log(f"已处理 {global_idx+1}/{total_files}: {filename}, 频率: {f_val}, 面积: {convex_hull_area:.2e}")
                
            except Exception as e:
                console.log(f"处理文件 {global_idx+1} 时出错: {str(e)}")
                frequencies.append(0)
                areas.append(0)
                hull_vertices_list.append(None)
    
    # Log summary statistics
    valid_areas = [a for a in areas if a > 0]
    if valid_areas:
        console.log(f"已处理的有效文件: {len(valid_areas)}")
        console.log(f"平均面积: {np.mean(valid_areas):.2e}")
        console.log(f"最小面积: {np.min(valid_areas):.2e}")
        console.log(f"最大面积: {np.max(valid_areas):.2e}")
    
    # Plot the results
    plot_scatter_area_vs_f(areas, frequencies)
    
    return areas, frequencies, hull_vertices_list


if __name__ == "__main__":
    # Clear console output file
    console.clear_file()
    
    # Read files
    dfs, filenames = select_and_read_files(file_type='csv')
    
    if len(dfs) > 0:
        # Process files and plot convex hull area vs frequency
        process_files_and_plot_area(dfs, filenames)
    else:
        console.log("未找到有效文件。")